from typing import Any, List, Optional
from tree_sitter import Node

from chernc.treediff.gumtree.tree.abstract_tree import AbstractTree
from chernc.treediff.gumtree.tree.tree import TreeLike


class TreeSitterNode(AbstractTree):
    def __init__(self, node: Node, parent: Optional["TreeLike"] = None) -> None:
        super(TreeSitterNode, self).__init__()
        self.parent = parent
        self._tree_sitter_node = node
        self._label = self.NO_LABEL
        self._pos = self._tree_sitter_node.start_byte
        self._length = self._tree_sitter_node.end_byte - self._tree_sitter_node.start_byte
        self._type = self._tree_sitter_node.type
        self._metadata = None
        
        self._text = self._tree_sitter_node.text.decode("utf-8") if self._tree_sitter_node.text else ""
        
        # Set label
        ts_name = self._tree_sitter_node.child_by_field_name("name")
        if ts_name is not None and ts_name.text is not None:
            self._label = ts_name.text.decode("utf-8")
            
        ts_operator = self._tree_sitter_node.child_by_field_name("operator")
        if ts_operator is not None and ts_operator.text is not None:
            self._label = ts_operator.text.decode("utf-8")
        
        comments = self._tree_sitter_node
        if "comment" in comments.grammar_name and comments.text is not None:
            self._label = comments.text.decode("utf-8")
        
        # if self._tree_sitter_node.type == "expression_statement" and self._tree_sitter_node.text is not None:
        #     self._label = self._tree_sitter_node.text.decode("utf-8")

        if self._tree_sitter_node.child_count == 0 and self._tree_sitter_node.text is not None:
            self._label = self._tree_sitter_node.text.decode("utf-8")

        # Set children
        for c in self._tree_sitter_node.children:
            if c.type in ["ERROR", "empty_statement"]:
                continue
            self.add_child(TreeSitterNode(c, parent=self))
        
        # print(self, self._tree_sitter_node.child_count)

    def deep_copy(self) -> TreeLike:
        new_node = TreeSitterNode(self._tree_sitter_node, parent=self.parent)
        return new_node

    def get_type(self) -> str:
        return self._type

    def set_type(self, t: str) -> None:
        self._type = t

    def __repr__(self) -> str:
        """Provide a string representation of the TreeSitterNode"""
        return f"TreeSitterNode(type=\"{self.get_type()}\",label=\"{self.get_label()}\")"
    
    def __str__(self) -> str:
        return f"TreeSitterNode(type=\"{self.get_type()}\",label=\"{self.get_label()}\")"

    def set_label(self, label: str) -> None:
        self._label = label

    def set_pos(self, pos: int) -> None:
        self._pos = pos

    def get_length(self) -> int:
        return self._length

    def set_length(self, length: int) -> None:
        self._length = length

    def get_label(self) -> str:
        return self._label

    def get_pos(self) -> int:
        return self._pos

    def get_metadata(self, key: str) -> Any:
        if self._metadata is None:
            return None
        return self._metadata.get(key)

    def set_metadata(self, key: str, value: Any) -> Any:
        if value is None:
            if self._metadata is None:
                return None
            else:
                return self._metadata.pop(key, None)
        if self._metadata is None:
            self._metadata = {}
        previous_value = self._metadata.get(key)
        self._metadata[key] = value
        return previous_value
    
    def to_tree_string(self) -> str:
        if self.has_label():
            return f"<{self.get_type()}: \"{self.get_label()}\">"
        else:
            return f"<{self.get_type()}>"
